var stageState = {
  PASS_NOT_SET:   0,    // 正常游戏状态
  EOF_MAIN_SEQ:   16,   // 主序列到底，继续update
  PASS_MAIN_SEQ:  32,   // 过关了，停止主序列，继续update
  STOP_STAGE:     48,   // 停止主序列，停止update
  FORCE_PASS:     99    // ???
};

function manager() {
  var eofstage = stageState.PASS_NOT_SET;
  var singleupdate = undefined;
  //这两个变量不用外面访问
  var mng = this;
  var stageName = undefined;    //关卡名

  //关卡的图片资源
  this.stageModal = [];
  //游戏的显示卷轴
  this.layer = new displayLayer();
  //游戏出场序列
  this.stageSeq = [];
  //主序列进度
  this.mainSeqOffset = 0;
  //游戏对象的路线表
  this.tracks = [];
  
//游戏中所有对象，按分组归类
  this.object_group = [];
  for(let i = 0;i < Const.MAX_GROUP;i++)  this.object_group[i] = [];

  // 碰撞组之间是否需要检测
  this.hit_table;

  this.keyEvent = function(event, keyCode) {
    //按键处理
    for(let player_item of player_glob.inst.pdata) {
      for(let keySet of Object.values(player_item.ctrl)) {
        if(keySet.key == keyCode) {
          if (event == 'keydown') {
//        	  console.log('keydown ' + keyCode)
            keySet.is_down = keySet.is_pressed = true;
          } else {
            keySet.is_down = keySet.is_pressed = false;
          }
        }
      }
    }
  };

  this.gameTick = 0;
  this.frameTick = 0;	// 不论游戏逻辑是否运算，都要加1
  function update() {
    //更新游戏对象
    for(let objg of mng.object_group) {
        for(let obj of objg) {
          if(obj.state > objectState.AI_DEATH)
            obj.update(mng.gameTick);
        }
    }
    //出场新对象
    let mainSeq = mng.stageSeq[0].objs;
    while (eofstage < stageState.EOF_MAIN_SEQ && mng.mainSeqOffset < mainSeq.length && mainSeq[mng.mainSeqOffset].starttime < mng.gameTick) {
      let objData = mainSeq[mng.mainSeqOffset];
      let modal = mng.stageModal[objData.modalid];
      let obj = game.new_object(modal, objData);

      mng.mainSeqOffset++;
    }
    
    if(eofstage < stageState.EOF_MAIN_SEQ && Const.TICK_JUMP_FROM > 0 && mng.gameTick < Const.TICK_JUMP_TO && mng.gameTick >= Const.TICK_JUMP_FROM) {
    	mng.gameTick = Const.TICK_JUMP_TO;
        while (eofstage < stageState.EOF_MAIN_SEQ && mng.mainSeqOffset < mainSeq.length && mainSeq[mng.mainSeqOffset].starttime < mng.gameTick) {
          mng.mainSeqOffset++;
        }
    }
  }

  function hittest() {
	for(let i = 0; i < Const.MAX_GROUP; i++) {
		for(let j = 0; j < Const.MAX_GROUP; j++) {
			if((mng.hit_table[i] >> j) & 1)  {
				//存在碰撞关系
				for(let sobject of mng.object_group[i]) {
					for(let dobject of mng.object_group[j]) {
						// 两个中有一个死了
						if(sobject.state <= objectState.AI_DEATH || dobject.state <= objectState.AI_DEATH)
							continue;
						if(sobject.modal.hit_rects.length &&			//存在碰撞矩形
							dobject.modal.hit_rects.length &&
							is_intersect(sobject, dobject)) {
							sobject.oncollide(dobject);
							dobject.oncollide(sobject);
						}
					}
				}
			}
		}
	}
  }
  
  function clearInput(){
    for(let player_item of player_glob.inst.pdata) {
        for(let keySet of Object.values(player_item.ctrl)) {
          keySet.is_pressed = false;
        }
      }
  }
  
//	-----------------
//  |   -----------   |
//  |  |     x     |  |
//  |   -----------   |
// -----------------
//运行时X Y坐标是 x点
//这样时判断会失败,但这个是飞行游戏，两上矩形是溅近到相交的
  function is_intersect(src, des) {
  	// 把两个碰撞矩形的原点（中点）重合的偏移
  	let x_offset = des.x - src.x;
  	let y_offset = des.y - src.y;
  	for(let i = 0; i < src.modal.hit_rects.length; i++) {
  		for(let j = 0; j < des.modal.hit_rects.length; j++) {
  			let srect = src.modal.hit_rects[i];
  			let drect = des.modal.hit_rects[j];
  			let sx1 = srect.x + x_offset;
  			let sx2 = sx1 + srect.w;
  			let sy1 = srect.y + y_offset;
  			let sy2 = sy1 + srect.h;
  			let dx2 = drect.x + drect.w;
  			let dy2 = drect.y + drect.h;
  			if( !(sx1 < drect.x && sx2 < drect.x || sx1 > dx2 && sx2 > dx2) &&
  				!(sy1 < drect.y && sy2 < drect.y || sy1 > dy2 && sy2 > dy2 ) )
  				return true;
  		}
  	}
  	return false;
  }
  
  this.removeInput = function() {
	  
  }

  let fpsElapseTime = 1000 / Const.FPS_MAX;
  let fpsNextTime = 0;
  function doStage() {
	let nowTime = (new Date()).getTime();
	if(nowTime < fpsNextTime)
		return false;
	fpsNextTime += fpsElapseTime;
	if(fpsNextTime < nowTime)	// fps赶不上，或者时间已经过了很久，直接强制跟上
		fpsNextTime = nowTime;
	  
    if(eofstage < stageState.FORCE_PASS) {
      // 磁撞测试,停止主序列后不再碰撞
      if(eofstage < stageState.STOP_STAGE) {

        // 更新飞机；子弹；背景
        update();
        // 碰撞检测
        hittest();
        if(eofstage < stageState.EOF_MAIN_SEQ)
          mng.gameTick++;

        //清除输入状态
        clearInput();
      } else if(singleupdate) {
        singleupdate.update(mng.gameTick);
      }
      //更新显示
      mng.layer.render();
      this.frameTick++;
      return true;
    }
    return false;
  }

  eofstage = stageState.PASS_NOT_SET;
  this.setpass = function(flag, single) {
    eofstage = flag;
    singleupdate = undefined;
    //过关时到玩家的生命加入全局变量里
    switch(eofstage) {
      case stageState.STOP_STAGE:
        singleupdate = single;
        break;
    }
  };
  
  this.new_object = function(modal, objData) {
	  let obj = this.new_object_base(modal, objData);
	  if(obj) {
		  obj.init();
		  game.object_group[obj.modal.group].push(obj);
		  return obj;
	  }
  }
  
  this.new_object_base = function(modal, objData) {
	if("vdata" in modal)
		console.log('new object ' + modal.vdata.id + "/" + modal.classid + " " + modal.vdata.imgfile + " " + 
				Math.floor(objData.x) + "," + Math.floor(objData.y) + "," + Math.floor(objData.vx) + "," + Math.floor(objData.vy) + "," + modal.layer)
	else
		debugger;
    switch (modal.classid) {
      case 0:			//玩家
        return new player(modal, objData);
      case 1:			//敌机
        return new airplane(modal, objData);
	  case 2:			//子弹
	    return new bullet(modal, objData);
      case 3:			//跟踪
        return new tracer_object(modal, objData);
      case 4:			//道具
    	return  new pickup_object(modal, objData);
      case 5:			//地面物体
        return new groundobject(modal, objData);
      case 6:			//地面
        return new backgroundobject(modal, objData);
      case 7:			//能做曲线运动的对象
        return new trackobject(modal, objData);
      case 8:			//对着玩家射击的子弹
        return new aimbullet(modal, objData);
      case 9:			//可以在上面放对象的对象(BOSS级)
        return new bigobject(modal, objData);
      case 10:		// 爆炸对象
        return new blastobject(modal, objData);
      case 11:		// 道具
    	return new container(modal, objData);
      case 12:		// 过关对象
        return new clearstageobject(modal, objData);
      case 13:		// 地面的路线对象
        return new groundTrackObject(modal, objData);
      case 14:		// 关卡开始动画
        return new startstageobject(modal, objData);
      case 15:		// 炮台
        return new redirector(modal, objData);
      case 16:		// 玩家飞机选择
    	return new playerselectobject(modal, objData);
      case 17:		// 玩家飞机管理器
        return new playermanager(modal, objData);
      case 18:		// 玩家跟踪弹
        return new bigtracertobject(modal, objData);
      case 19:		// 玩家自动定向弹
        return new expaimbullet(modal, objData);
      case 20:		// 玩家打中慢速弹
        return new geardown(modal, objData);
      default: return;
    }
  }
  
  this.new_object_param = function(param, father) {
	  let modal = this.stageModal[param.modalid];
	  if(father) {
		  let obj;
		  if(modal.startparent()) {
			  obj = this.new_object(modal, {
				  x : father.x + param.x,
				  y : father.y + param.y,
				  vx : param.vx,
				  vy : param.vy
			  });
		  } else {
			  obj = this.new_object(modal, param);
		  }

		  if(obj)
			  obj.setparent(father);
		  return obj;
	  } else {
		  return this.new_object(modal, param);
	  }
  }
  
  this.new_object_seq = function(seq, index, father) {
	  return this.new_object_param(seq.objs[index], father);
  }

  this.appTicker = function () {};
  this.stageSound = {};

  loadResource(function (stageRes) {
    let stageData = PIXI.loader.resources[mng.stageName + '/stage.json'].data;
    for(let m of stageData.modals) {
      let mod = new modal(mng.stageName, stageRes, m);
      mng.stageModal.push(mod);
    }
    mng.stageSeq = stageData.seqs;
    mng.tracks = stageData.tracks;
    mng.hit_table = stageData.hittable;

    mng.appTicker = doStage;
    fpsNextTime = (new Date()).getTime();
  });
}